using System.Collections;
using System.Diagnostics;

namespace Kook;

internal static class CollectionExtensions
{
    //public static IReadOnlyCollection<TValue> ToReadOnlyCollection<TValue>(this IReadOnlyCollection<TValue> source)
    //    => new CollectionWrapper<TValue>(source, () => source.Count);

    public static IReadOnlyCollection<TValue> ToReadOnlyCollection<TValue>(this ICollection<TValue> source) =>
        new CollectionWrapper<TValue>(source, () => source.Count);

    //public static IReadOnlyCollection<TValue> ToReadOnlyCollection<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> source)
    //    => new CollectionWrapper<TValue>(source.Select(x => x.Value), () => source.Count);

    public static IReadOnlyCollection<TValue> ToReadOnlyCollection<TKey, TValue>(this IDictionary<TKey, TValue> source) =>
        new CollectionWrapper<TValue>(source.Values, () => source.Count);

    public static IReadOnlyCollection<TValue> ToReadOnlyCollection<TValue, TSource>(this IEnumerable<TValue> query,
        IReadOnlyCollection<TSource> source) =>
        new CollectionWrapper<TValue>(query, () => source.Count);

    public static IReadOnlyCollection<TValue> ToReadOnlyCollection<TValue>(this IEnumerable<TValue> query, Func<int> countFunc) =>
        new CollectionWrapper<TValue>(query, countFunc);

#if !NET6_0_OR_GREATER
    public static TSource? MinBy<TSource, TKey>(
        this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector) =>
        source.OrderBy(keySelector).FirstOrDefault();

    public static TSource? MaxBy<TSource, TKey>(
        this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector) =>
        source.OrderByDescending(keySelector).FirstOrDefault();

    public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunkSize) =>
        source
            .Select((x, i) => new { Index = i, Value = x })
            .GroupBy(x => x.Index / chunkSize)
            .Select(x => x.Select(v => v.Value));
#endif
}

[DebuggerDisplay("{DebuggerDisplay,nq}")]
internal readonly struct CollectionWrapper<TValue> : IReadOnlyCollection<TValue>
{
    private readonly IEnumerable<TValue> _query;
    private readonly Func<int> _countFunc;

    //It's okay that this count is affected by race conditions - we're wrapping a concurrent collection and that's to be expected
    public int Count => _countFunc();

    public CollectionWrapper(IEnumerable<TValue> query, Func<int> countFunc)
    {
        _query = query;
        _countFunc = countFunc;
    }

    private string DebuggerDisplay => $"Count = {Count}";

    public IEnumerator<TValue> GetEnumerator() => _query.GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() => _query.GetEnumerator();
}
